//
// Created by 崔世强 on 2018/3/20.
// Copyright (c) 2018 Facebook. All rights reserved.
//

import Foundation
import Moya
import SwiftHash
import SwiftyJSON


let imApi = MoyaProvider<IMApi>()



struct IM {
    static let provider = MoyaProvider<IMApi>()
    
    static func request(
        _ target: IMApi,
        callbackQueue:DispatchQueue? = DispatchQueue.global(),
        success successCallback: @escaping (JSON) -> Void,
        error errorCallback: @escaping (Int) -> Void,
        failure failureCallback: @escaping (MoyaError) -> Void,
        progress progressBlock: ProgressBlock? = .none
        ) {
        provider.request(target,callbackQueue: callbackQueue,progress: progressBlock) { result in
            switch result {
            case let .success(response):
                do {
                    //如果数据返回成功则直接将结果转为JSON
                    _ = try response.filterSuccessfulStatusCodes()
                    let json = JSON(response.data)
                    successCallback(json)
                }
                catch let error {
                    //如果数据获取失败，则返回错误状态码
                    errorCallback((error as! MoyaError).response!.statusCode)
                }
            case let .failure(error):
                //如果连接异常，则返沪错误信息（必要时还可以将尝试重新发起请求）
                //if target.shouldRetry {
                //    retryWhenReachable(target, successCallback, errorCallback,
                //      failureCallback)
                //}
                //else {
                failureCallback(error)
                //}
            }
        }
    }
}





func reqSuccess(_ code: String) -> Bool {
    return code == "10000"
}

enum IMApi {
    case fetchUserInfo(userIds: [Int])  //拉取用户信息
    case getAUserInfo(userId: Int) //获取单个用户信息
    case getGroupInfo(groupId: Int) //获取群组信息
    case getFamilyMembers(userId: Int, currentPage: Int)  //获取家族成员信息
    case getGroupUsers(groupId: Int) //获取群用户信息
    case setNickName(groupId: Int, userId: Int, nickName: String)//设置群用户自身昵称
    case modifyGroupName(groupId: Int, userId: Int, name: String)//设置群名称
    case modifyGroupAnnouncement(groupId: Int, userId: Int, announcement: String)//修改群公告
    case muteAll(groupId: Int, userId: Int)
    case noDisturb(userId: Int,sessionId:Int,cType:Int)//免打扰
    case cancelNoDisturb(userId: Int,sessionId:Int,cType:Int)//取消免打扰
    case unMuteAll(groupId: Int, userId: Int)
    case quitGroup(groupId: Int, userId: Int)//退出群组
    case deleteGroupMembers(groupId: Int, manageId: Int, userIds: [Int]) //删除群成员
    case addGroupMembers(groupId: Int, manageId: Int, userIds: [Int]) //添加群成员
    case chatOpen(userId:Int) //获取聊天功能是否开启
    case setChatOpen(userId:Int,open:Bool) //开启或关闭聊天功能
    case fetchDirectContact(userId:Int, currentPage:Int, pageSize:Int) //获取直系联系人信息
    case fetchParentUser(userId:Int) //获取上级联系人信息
    case createNewGroup(name:String?, type: Int, createUserId:Int, ids: [Int])  //建立新群
    case getSensitiveVersion//获取敏感词版本
    case login(userName:String,pwd:String)//登录
    case register(userName:String,pwd:String,validateCode:String)//注册
    case modifyPwd(userId:Int,oldPwd:String,newPwd:String)//修改密码
    case modifyInfo(userId:Int, name:String?, avatar:String?, gender:Int?)//修改当前登录用户信息
    case upload(dir:String,file: String, filename: String)//上传文件
}

extension IMApi: TargetType {
    public var baseURL: URL {
        return IM_HTTP_SERVER_URL
//        return URL(string:"http://localhost:8080/")!
        //        return URL(string: "https://apprn.tingmimi.net/")!
    }
    
    //各个请求的具体路径
    public var path: String {
        switch self {
        case .fetchUserInfo:
            return "im/batchUserInfo"
        case .getFamilyMembers:
            return "im/getFamilyMembers"
        case .getGroupUsers(let groupId):
            return "im/group/\(groupId)/users"
        case .modifyGroupAnnouncement:
            return "im/group/modifyGroupAnnouncement"
        case .setNickName:
            return "im/group/nickName"
        case .modifyGroupName:
            return "im/group/modifyGroupName"
        case .muteAll(let groupId,let userId):
            return "im/group/\(groupId)/mute/\(userId)"
        case .unMuteAll(let groupId, let userId):
            return "im/group/\(groupId)/unmute/\(userId)"
        case .quitGroup(let groupId, let userId):
            return "im/group/\(groupId)/\(userId)"
        case .deleteGroupMembers:
            return "im/group/deleteGroupUser"
        case .addGroupMembers(let groupId, _ , _):
            return "im/group/\(groupId)/addGroupUser"
        case .getGroupInfo(let groupId):
            return "im/group/\(groupId)"
        case .getAUserInfo(let userId):
            return "im/users/\(userId)"
        case .noDisturb(let userId, let sessionId,let cType):
            return "im/group/\(userId)/noDisturb/\(sessionId)/\(cType)"
        case .cancelNoDisturb(let userId, let sessionId,let cType):
            return "im/group/\(userId)/cancelNoDisturb/\(sessionId)/\(cType)"
        case .chatOpen(let userId):
            return "im/users/chatSwitch/\(userId)"
        case .setChatOpen(let userId,let open):
            return "im/users/chatSwitch/\(userId)/\(open ? 1 : 0)"
        case .fetchDirectContact:
            return "im/getLinealUsers"
        case .fetchParentUser:
            return "im/getParentUser"
        case .createNewGroup:
            return "im/group/new"
        case .getSensitiveVersion:
            return "im/sensitive/version"
        case .login:
            return "im/users/login"
        case .register:
            return "im/users/register"
        case .modifyPwd:
            return "im/users/modifyPwd"
        case .modifyInfo:
            return "im/users/modifyInfo"
        case .upload:
            return "im/file/upload"
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .fetchUserInfo:
            return .get
        case .getFamilyMembers:
            return .get
        case .getGroupUsers:
            return .get
        case .setNickName:
            return .put
        case .modifyGroupName:
            return .put
        case .modifyGroupAnnouncement:
            return .put
        case .muteAll:
            return .put
        case .unMuteAll:
            return .put
        case .quitGroup:
            return .delete
        case .deleteGroupMembers:
            return .put
        case .addGroupMembers:
            return .put
        case .noDisturb:
            return .put
        case .cancelNoDisturb:
            return .put
        case .setChatOpen:
            return .put
        case .createNewGroup:
            return .post
        case .login:
            return .post
        case .register:
            return .post
        case .modifyPwd:
            return .post
        case .modifyInfo:
            return .post
        case .upload:
            return .post
        default:
            return .get
        }
    }
    
    //请求任务事件（这里附带上参数）
    public var task: Task {
        switch self {
        case .fetchUserInfo(let userIds):
            return .requestParameters(parameters: ["ids": userIds], encoding: URLEncoding.queryString)
        case .getFamilyMembers(let userId, let currentPage):
            return .requestParameters(parameters: ["id": userId, "currentPage": currentPage], encoding: URLEncoding.queryString)
        case .getGroupUsers(let groupId):
            return .requestParameters(parameters: ["groupId": groupId], encoding: URLEncoding.queryString)
        case .setNickName(let groupId, let userId, let nickName):
            return .requestParameters(parameters: ["groupId": groupId, "userId": userId, "nickName": nickName], encoding: JSONEncoding.default)
        case .modifyGroupName(let groupId, let userId, let name):
            return .requestParameters(parameters: ["groupId": groupId, "userId": userId, "name": name], encoding: JSONEncoding.default)
        case .modifyGroupAnnouncement(let groupId, let userId, let announcement):
            return .requestParameters(parameters: ["groupId": groupId, "userId": userId, "announcement": announcement], encoding: JSONEncoding.default)
        case .muteAll(let groupId, let userId):
            return .requestParameters(parameters: ["groupId": groupId, "userId": userId], encoding: URLEncoding.queryString)
        case .unMuteAll(let groupId, let userId):
            return .requestParameters(parameters: ["groupId": groupId, "userId": userId], encoding: URLEncoding.queryString)
        case .quitGroup(_, _):
//            return .requestParameters(parameters: ["groupId": groupId, "userId": userId], encoding: URLEncoding.queryString)
            return .requestPlain
        case .deleteGroupMembers(let groupId, let manageId, let userIds):
            return .requestParameters(parameters: ["groupId": groupId, "managerId": manageId, "targetUserId": userIds], encoding: JSONEncoding.default)
        case .addGroupMembers(_, let managerId, let userIds):
            return .requestParameters(parameters: ["createUserId":managerId,"ids": userIds], encoding: JSONEncoding.default)
//            return .requestCompositeParameters(bodyParameters: ["createUserId":managerId,"ids": userIds], bodyEncoding: JSONEncoding.default, urlParameters: ["groupId": groupId])
        case .getGroupInfo(let groupId):
            return .requestParameters(parameters: ["groupId": groupId], encoding: URLEncoding.queryString)
        case .getAUserInfo(let userId):
            return .requestParameters(parameters: ["userId": userId], encoding: URLEncoding.queryString)
        case .noDisturb(let userId,let sessionId,let cType):
            return .requestParameters(parameters: ["userId":userId,"sessionId":sessionId,"ctype":cType], encoding: URLEncoding.queryString)
        case .cancelNoDisturb(let userId,let sessionId,let cType):
            return .requestParameters(parameters: ["userId":userId,"sessionId":sessionId,"ctype":cType], encoding: URLEncoding.queryString)
        case .chatOpen:
            return .requestPlain
        case .fetchDirectContact(let userId, let currentPage, let pageSize):
            return .requestParameters(parameters: ["userId": userId, "currentPage": currentPage, "pageSize": pageSize], encoding: URLEncoding.queryString)
        case .fetchParentUser(let userId):
            return .requestParameters(parameters: ["userId": userId], encoding: URLEncoding.queryString)
        case .createNewGroup(let name, let type, let createUserId, let ids):
            return .requestCompositeParameters(bodyParameters: ["name": name, "type": type, "createUserId": createUserId, "ids": ids], bodyEncoding: JSONEncoding.default, urlParameters:[:])
        case .login(let userName, let pwd):
            return .requestParameters(parameters: ["userName": userName, "pwd": pwd], encoding: URLEncoding.httpBody)
        case .register(let userName, let pwd,_):
            return .requestParameters(parameters: ["phone":userName,"pwd":pwd], encoding: URLEncoding.httpBody)
        case .modifyPwd(let userId,let oldPwd,let newPwd):
            return .requestParameters(parameters: ["userId":userId,"pwd":oldPwd,"newPwd":newPwd], encoding: URLEncoding.httpBody)
        case .modifyInfo(let userId, let name, let avatar, let gender):
            return .requestParameters(parameters: ["userId":userId,"name":name ?? "","avatar":avatar ?? "", "gender": gender ?? 0], encoding: URLEncoding.httpBody)
        case .upload(let dir,let file,let filename):
            do {
                let data = try Data(contentsOf: URL(fileURLWithPath: file))
                let encryptedData = try Cipher.shared.encrypt(data: data)
                let fileData = MultipartFormData(provider: .data(encryptedData), name: "file", fileName: filename, mimeType: "application/octet-stream")
                let dirData = MultipartFormData(provider: .data(dir.data(using: .utf8)!), name: "dir")
                return .uploadMultipart([fileData, dirData])
            } catch {
                print("encrypt error: \(error)")
                return .requestPlain
            }
        default:
            return .requestPlain
        }
    }
    
    //是否执行Alamofire验证
    public var validate: Bool {
        return false
    }
    
    //这个就是做单元测试模拟的数据，只会在单元测试文件中有作用
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }
    
    //请求头
    public var headers: [String: String]? {
        let appkey = "temp_test"
        let token = "1545126907123721"
        let datetime = TimeUtil.instance.string(Date())
        let sign = MD5(appkey + token + datetime)
        let headers = ["appkey": appkey, "token": token, "datetime": datetime, "sign": sign]
        
        return headers
    }
}

class AesDecryptPlugin: PluginType {
    
    /// Called after a response has been received, but before the MoyaProvider has invoked its completion handler.
    func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
        print("000000000000 插件触发")
    }
    
    /// Called to modify a result before completion.
    func process(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> Result<Moya.Response, MoyaError> {
        if case .success(let response) = result {
            do {
                let data = response.data
                let decryptedData = try Cipher.shared.decrypt(data: data)
                return .success(Response(statusCode: response.statusCode, data: decryptedData,request: response.request,response: response.response))
            }catch {
                
            }
        }
        return result
    }
}





let imResources = MoyaProvider<IMResources>(plugins: [AesDecryptPlugin()])

enum IMResources {
    case file(fileName:String)
}

//定义下载的DownloadDestination（不改变文件名，同名文件不会覆盖）
private let DefaultDownloadDestination: DownloadDestination = { temporaryURL, response in
    return (DefaultDownloadDir.appendingPathComponent(response.suggestedFilename!), [.createIntermediateDirectories,.removePreviousFile]) //创建中间不存在的目录，自动覆盖同名文件
}

//默认下载保存地址（用户缓存目录）
let DefaultDownloadDir: URL = {
    let directoryURLs = FileManager.default.urls(for: .cachesDirectory,
                                                 in: .userDomainMask)
    let fileDir = directoryURLs[0].appendingPathComponent("files", isDirectory: true)
    return fileDir
}()

extension IMResources: TargetType {
    
    public var baseURL: URL {
        return URL(string: "\(IM_HTTP_SERVER_URL_STRING)im/file/download/")!
    }
    
    //各个请求的具体路径
    public var path: String {
        switch self {
        case .file(let fileName):
            return "files/\(fileName)"
        }
    }
    
    var method: Moya.Method {
        return .get
    }
    
    //请求任务事件（这里附带上参数）
    public var task: Task {
        switch self {
        case .file:
            return .downloadDestination(DefaultDownloadDestination)
        }
    }
    
    //是否执行Alamofire验证
    public var validate: Bool {
        return false
    }
    
    //这个就是做单元测试模拟的数据，只会在单元测试文件中有作用
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }
    
    //请求头
    public var headers: [String: String]? {
        return nil
    }
}
